package net.zxteam.reusable.java.diff;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import net.zxteam.reusable.java.diff.DiffFolderInfo.STATE;

class DiffFolderImpl extends DiffFolder {

	private File headFolder;
	private File subordinateFolder;
	
	@Override
	public void setHeadFolder(File folder) { synchronized (this) { headFolder = folder; }}

	@Override
	public void setSubordinateFolder(File folder) { synchronized (this) { subordinateFolder = folder; }}

	@Override
	public DiffFolderInfo[] compare() throws IOException {

		File main, child;
		String ignoreMask;
		DiffFolderComparator comparator;
		synchronized (this) {

			main = headFolder; 
			child = subordinateFolder; 
			ignoreMask = this.getIgnoreMask();
			comparator = this.getComparator();
		}

		HashSet<String> ignoreMaskSet = new HashSet<String>();
		if(ignoreMask != null)
			for(String s : ignoreMask.split(";"))
				if(!ignoreMaskSet.contains(s))
					ignoreMaskSet.add(s);

		HashMap<String, DiffFolderInfo> unionTable = new HashMap<String, DiffFolderInfo>();

		for(File f : main.listFiles())
			recurentFillHeadFolder(f, unionTable, ignoreMaskSet);

		for(File f : child.listFiles())
			recurentFillSubordinateFolderAndCompare(f, unionTable, comparator, ignoreMaskSet);

		ArrayList<DiffFolderInfo> list = new ArrayList<DiffFolderInfo>();

		for(DiffFolderInfo dfInfo : unionTable.values()) {

			if(!dfInfo.getState().equals(STATE.NOT_MODIFIED))
				list.add(dfInfo);
		}

		return list.toArray(new DiffFolderInfo[list.size()]);
	}

	private void recurentFillHeadFolder(File file, Map<String, DiffFolderInfo> table, Set<String> ignoreMaskSet) throws IOException {

		if(file == null || table == null)
			throw new IllegalArgumentException();

		if(ignoreMaskSet.contains(file.getName()))
			return;
		
		File relativeFile = net.zxteam.reusable.java.io.File.getRelativeFile(file, this.headFolder);

		DiffFolderInfo dfInfo = new DiffFolderInfo(relativeFile);
		dfInfo.setState(STATE.REMOVED);

		table.put(relativeFile.getPath(), dfInfo);

		if(file.isDirectory()) {

			File[] childs = file.listFiles();
			for(File f : childs) 
				recurentFillHeadFolder(f, table, ignoreMaskSet);
		}
	}

	private void recurentFillSubordinateFolderAndCompare(File file, Map<String, DiffFolderInfo> table, DiffFolderComparator comparator, Set<String> ignoreMaskSet) throws IOException {

		if(file == null || table == null || comparator == null)
			throw new IllegalArgumentException();

		if(ignoreMaskSet.contains(file.getName()))
			return;

		File relativeFile = net.zxteam.reusable.java.io.File.getRelativeFile(file, this.subordinateFolder);

		if(table.containsKey(relativeFile.getPath())) {

			DiffFolderInfo dfInfo = table.get(relativeFile.getPath()); 

			boolean isFileModified = comparator.IsModified(new File(this.headFolder, relativeFile.getPath()), new File(this.subordinateFolder, relativeFile.getPath()));

			dfInfo.setState(isFileModified ? STATE.MODIFIED : STATE.NOT_MODIFIED);
		}
		else {

			DiffFolderInfo dfInfo = new DiffFolderInfo(relativeFile);
			dfInfo.setState(STATE.ADDED);

			table.put(relativeFile.getPath(), dfInfo);
		}

		if(file.isDirectory()) {

			File[] childs = file.listFiles();
			for(File f : childs) 
				recurentFillSubordinateFolderAndCompare(f, table, comparator, ignoreMaskSet);
		}
	}
}
